package com.baicaoyuan.web.service;

import com.baicaoyuan.web.common.StringUtils;
import com.baicaoyuan.web.common.TimeUtils;
import com.baicaoyuan.web.enums.CashOutStatusEnum;
import com.baicaoyuan.web.enums.LevelEnum;
import com.baicaoyuan.web.model.CashOutDO;
import com.baicaoyuan.web.model.UserDO;
import com.baicaoyuan.web.repository.CashOutRepository;
import com.baicaoyuan.web.request.br.BCashOutApplyRequest;
import com.baicaoyuan.web.response.CashOutPersonResponse;
import com.baicaoyuan.web.response.CashOutResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class CashOutService {

    private static final Lock LOCK = new ReentrantLock(true);
    @Autowired
    CashOutRepository cashOutRepository;

    @Autowired
    UserService userService;

    @Autowired
    ScoreDetailService scoreDetailService;

    public void save(BCashOutApplyRequest request) {
        CashOutDO cashOut = new CashOutDO();
        BeanUtils.copyProperties(request, cashOut);
        cashOut.setUserFk(request.getUserId());

        UserDO user = userService.findOne(request.getUserId());
        Objects.requireNonNull(user);
        cashOut.setTelephone(user.getTelephone());
        cashOut.setUserName(user.getUserName());
        cashOut.setMoney(scoreToMoney(request.getScore()));
        cashOut.setCreateTime(TimeUtils.getCurrentTime());
        cashOut.setStatus(CashOutStatusEnum.COMMIT.getStatus());

        Objects.requireNonNull(cashOutRepository.save(cashOut));
    }

    public void reject(Long id) {
        Integer i = this.cashOutRepository.updateStatus(id, CashOutStatusEnum.REJECT.getStatus());
        if (i == 0) {
            throw new RuntimeException();
        }
    }


    public List<CashOutResponse> getCashOutApplies(String telephone, String status, Integer page, Integer size) {
        List<CashOutDO> list = this.cashOutRepository.getCashOuts(StringUtils.plusPercent(telephone), StringUtils.plusPercent(status), (page - 1) * size, size);
        List<CashOutResponse> result = new ArrayList<>();
        list.forEach(x -> {
            CashOutResponse r = new CashOutResponse();
            BeanUtils.copyProperties(x, r);
            result.add(r);
        });

        return result;
    }

    public Integer getCountOfAll(String telephone, String status) {
        return this.cashOutRepository.countAllByStatusLikeAndTelephoneLike(status, telephone);
    }

    public List<CashOutPersonResponse> getPersonApplies(Long userId, Integer page, Integer size) {
        List<CashOutDO> list = this.cashOutRepository.findByUserFkOrderByCreateTimeDesc(userId, new PageRequest(page - 1, size));
        List<CashOutPersonResponse> result = new ArrayList<>();
        list.forEach(x -> {
            CashOutPersonResponse r = new CashOutPersonResponse();
            BeanUtils.copyProperties(x, r);
            result.add(r);
        });

        return result;
    }

    /**
     * 计入重入公平锁，线程按先后顺序来获取锁
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    public void checkSuccess(Long id) {
        try {
            LOCK.lock();

            CashOutDO cashOut = this.cashOutRepository.findOne(id);
            Long userId = cashOut.getUserFk();
            UserDO user = this.userService.findOne(userId);
            System.out.println("账户：" + user.getScoreTotal().doubleValue() + "申请：" + cashOut.getScore().doubleValue());
            if (cashOut.getScore().doubleValue() > user.getScoreTotal().doubleValue()) {
                throw new RuntimeException("提现积分不能大于已有积分");
            }

            this.userService.scorePlus(userId, cashOut.getScore().negate());
            Integer r = this.cashOutRepository.updateStatus(id, CashOutStatusEnum.SUCCESS.getStatus());
            if (r == 0) {
                throw new RuntimeException();
            }
            scoreDetailService.save(userId, "", cashOut.getScore().negate(), null, LevelEnum.Me);
        } catch (Exception ex) {
            throw ex;
        } finally {
            LOCK.unlock();
        }
    }

    /**
     * 判断是否可以提现
     */
    private boolean canCashOut(Long userId, BigDecimal score) {
        UserDO user = this.userService.findOne(userId);
        return user.getScoreTotal().doubleValue() >= score.doubleValue();
    }


    /**
     * 积分转金额
     * 1:1 比例
     *
     * @param score
     * @return
     */
    private BigDecimal scoreToMoney(BigDecimal score) {
        return score;
    }
}
